using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using EarthGeospatial;
using Geometry;
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Newtonsoft.Json.Linq;
using EarthUtility;
using UnityEngine;

namespace Cesium3DTilesSelection
{

    public class BingMapsTileProvider : QuadtreeRasterOverlayTileProvider
    {
        private string _urlTemplate;
        private List<string> _subdomains;
        public BingMapsTileProvider(RasterOverlay owner, IPrepareRendererResources pPrepareRendererResources, string baseUrl,
       string urlTemplate, List<string> subdomanins, int width, int height, int minimumLevel, int maximumLevel, string culture) :
       base(owner, pPrepareRendererResources,
        new Projection(new WebMercatorProjection()),
       new QuadtreeTilingScheme(WebMercatorProjection.computeMaximumProjectedRectangle(Ellipsoid.WGS84), 2, 2),
       WebMercatorProjection.computeMaximumProjectedRectangle(Ellipsoid.WGS84),
        minimumLevel, maximumLevel, width, height)
        {

            this._urlTemplate = urlTemplate;
            this._subdomains = subdomanins;
            UriBuilder ub = new UriBuilder(this._urlTemplate);

            Uri uri = new Uri(this._urlTemplate);
            if (this._urlTemplate.Contains("n=z"))
            {
                ub.Query += "n=z";
            }

            string resolvedUrl = baseUrl + ub.ToString();
            resolvedUrl = Regex.Replace(resolvedUrl, @"\{\w+\}", placeholder =>
              {
                  if (placeholder.Value == "{culture}")
                      return culture;
                  return placeholder.Value;
              });
        }

        private static string tileXYToQuadKey(int level, int x, int y)
        {
            string quadkey = "";
            for (int i = level; i >= 0; --i)
            {
                int bitmask = (1 << i);
                int digit = 0;

                if ((x & bitmask) != 0)
                {
                    digit |= 1;
                }

                if ((y & bitmask) != 0)
                {
                    digit |= 2;
                }

                quadkey += digit;
            }

            return quadkey;
        }
        protected override async UniTask<LoadedRasterOverlayImage> loadQuadtreeTileImage(QuadtreeTileID tileID)
        {
            string url = Regex.Replace(this._urlTemplate, @"\{\w+\}", key =>
            {
                if (key.Value == "{quadkey}")
                {
                    return tileXYToQuadKey(
                        tileID.level,
                        tileID.x,
                        tileID.computeInvertedY(this.tilingScheme));
                }
                if (key.Value == "{subdomain}")
                {
                    int subdomainIndex = (tileID.level + tileID.x + tileID.y) % this._subdomains.Count;
                    return this._subdomains[subdomainIndex];
                }
                return key.Value;
            });

            LoadTileImageFromUrlOptions options = new LoadTileImageFromUrlOptions();
            options.allowEmptyImages = true;
            options.moreDetailAvailable = tileID.level < this.MaximumLevel;
            options.rectangle = this.tilingScheme.tileToRectangle(tileID);

            GlobeRectangle tileRectangle = Projection.unprojectRectangleSimple(this.pProjection, options.rectangle);

            // Cesium levels start at 0, Bing levels start at 1
            int bingTileLevel = tileID.level + 1;

            // for (const CreditAndCoverageAreas& creditAndCoverageAreas : _credits) {
            //   for (const CoverageArea& coverageArea :
            //        creditAndCoverageAreas.coverageAreas) {
            //     if (coverageArea.zoomMin <= bingTileLevel &&
            //         bingTileLevel <= coverageArea.zoomMax &&
            //         coverageArea.rectangle.computeIntersection(tileRectangle)
            //             .has_value()) {
            //       tileCredits.push_back(creditAndCoverageAreas.credit);
            //       break;
            //     }
            //   }
            // }

            return await this.loadTileImageFromUrl(url, new Dictionary<string, string>(), options);
        }


    }
    public class BingMapsRasterOverlay : RasterOverlay
    {
        private string name;
        private string url;
        private string key;
        private string mapStyle;
        private string culture;

        public BingMapsRasterOverlay(string name, string bingurl, string key, string mapStyle, string culture)
        {
            this.name = name;
            this.url = bingurl;
            this.key = key;
            this.mapStyle = mapStyle;
            this.culture = culture;
        }

        public override async UniTask<RasterOverlayTileProvider> createTileProvider(IPrepareRendererResources pPrepareRendererResources, RasterOverlay pOwner)
        {
            var metadataUrl = new Uri(new Uri(this.url), "REST/v1/Imagery/Metadata/" + this.mapStyle).ToString();
            UriBuilder ub = new UriBuilder(metadataUrl);
            ub.Query += "incl=ImageryProviders";
            ub.Query += "key=" + this.key;
            ub.Query += "uriScheme=https";
            pOwner = pOwner ? pOwner : this;
            string requestURL = ub.ToString();
            var responseJson = await http.Get(requestURL);
            var response = JObject.Parse(responseJson);
            var pResource = response["/resourceSets/0/resources/0"];
            if (!pResource.HasValues)
            {


            }
            int width = JsonHelpers.getUint32OrDefault(pResource, "imageWidth", 256);
            int height = JsonHelpers.getUint32OrDefault(pResource, "imageHeight", 256);
            int maximumLevel = JsonHelpers.getUint32OrDefault(pResource, "zoomMax", 30);

            List<string> subdomains = JsonHelpers.getStrings(pResource, "imageUrlSubdomains");
            string urlTemplate = JsonHelpers.getStringOrDefault(pResource, "imageUrl", "");
            if (string.IsNullOrEmpty(urlTemplate))
            {
                Debug.Log("Bing Maps tile imageUrl is missing or empty.");
            }
            return new BingMapsTileProvider(pOwner, pPrepareRendererResources, this.url, urlTemplate, subdomains, width, height, 0, maximumLevel, culture);
        }

    }
}